/*
 * 计算校验和
 */
#include <unistd.h>
#include <netinet/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include "checksum.h"


/*
 * 计算校验和
 */
u_int16_t checksum(u_int32_t init, u_int8_t *addr, size_t count)
{
	u_int32_t	sum		= init;

	while( count > 1 )
	{
		sum += ntohs( *(u_int16_t*) addr);
		addr += 2;
		count -= 2;
	}

	if( count > 0 )
	{
		sum += *(u_int8_t *)addr;
	}

	while( sum >> 16 )
	{
		sum = (sum & 0xffff) + (sum >> 16);
	}

	return (u_int16_t)~sum;
}
/*
 * 计算IP包的校验和
 */
u_int16_t ip_checksum(struct iphdr* iphdrp)
{
	return checksum(0, (u_int8_t*)iphdrp, iphdrp->ihl << 2);
}
/*
 * 设置IP的校验和
 */
void set_ip_checksum(struct iphdr* iphdrp)
{
	iphdrp->check = 0;
	iphdrp->check = htons( checksum(0, (u_int8_t*)iphdrp, iphdrp->ihl << 2) );
}
/*
 * TCP校验和
 */
u_int16_t tcp_checksum2(struct iphdr* iphdrp, struct tcphdr* tcphdrp)
{
	size_t		tcplen		= ntohs(iphdrp->tot_len) - (iphdrp->ihl << 2);
	u_int32_t	cksum		= 0;

	cksum += ntohs((iphdrp->saddr >> 16) & 0x0000ffff);
	cksum += ntohs(iphdrp->saddr & 0x0000ffff);
	cksum += ntohs((iphdrp->daddr >> 16) & 0x0000ffff);
	cksum += ntohs(iphdrp->daddr & 0x0000ffff);
	cksum += iphdrp->protocol & 0x00ff;
	cksum += tcplen;

	return checksum(cksum, (u_int8_t *)tcphdrp, tcplen);
}
/*
 */
u_int16_t tcp_checksum1(struct iphdr* iphdrp)
{
	struct tcphdr*		tcphdrp		= (struct tcphdr*)((u_int8_t*)iphdrp + (iphdrp->ihl << 2));

	return tcp_checksum2(iphdrp, tcphdrp);
}
/*
 */
void set_tcp_checksum2(struct iphdr* iphdrp, struct tcphdr* tcphdrp)
{
	tcphdrp->check = 0;
	tcphdrp->check = htons(tcp_checksum2(iphdrp, tcphdrp));
}
/*
 */
void set_tcp_checksum1(struct iphdr* iphdrp)
{
	struct tcphdr*		tcphdrp		= (struct tcphdr*)((u_int8_t*)iphdrp + (iphdrp->ihl << 2));

	set_tcp_checksum2(iphdrp, tcphdrp);
}

